using System;
using System.Collections.Generic;
using SharpDX.DirectInput;
using System.Windows.Forms;

//http://sharpdx.com/forum/4-general/3438-joystick-acquisition
namespace HID
{
    public class HIDControl
    {
        DirectInput directInput;
        Guid deviceGuid;

        JoystickState jmDeviceState;
        Joystick  jmDevice;

        KeyboardState kDeviceState;
        Keyboard  kDevice;


        //state for catching analogs. 
        bool deviceLock = false;
        float deviceStateX = 0f;
        float deviceStateY = 0f;
        float deviceStateZ = 0f;
        float deviceStateXr = 0f;
        float deviceStateYr = 0f;
        float deviceStateZr = 0f;

        public  HIDControl (  )
        {
            directInput = new DirectInput();// Initialize DirectInput
            deviceGuid = Guid.Empty;// Find a Joystick Guid

        }

   
        class Devices//holds a lit of all devices found
        {
            public int id  { get;set;}
            public string name { get;set;}
            public Guid guid { get; set; }
            public string type { get; set; }
        };
        List<Devices> devices = new List<Devices>();

        public List<string> getDevices()
        {
            List<string> devicesList = new List<string>();//Just a list to return for selection.
           
            int i=0;//find all devices and save the guid, name, and ID.
            foreach (DeviceInstance deviceInstance in directInput.GetDevices(DeviceType.Gamepad, DeviceEnumerationFlags.AllDevices))
            { devicesList.Add(deviceInstance.Type + "_" + deviceInstance.InstanceName + ":" + i); devices.Add(new Devices { type = deviceInstance.Type.ToString() , name = deviceInstance.InstanceName, guid = deviceInstance.InstanceGuid, id = i++ }); }
            i = 0;
            foreach (DeviceInstance deviceInstance in directInput.GetDevices(DeviceType.Joystick, DeviceEnumerationFlags.AllDevices))
            { devicesList.Add(deviceInstance.Type + "_" + deviceInstance.InstanceName + ":" + i); devices.Add(new Devices { type = deviceInstance.Type.ToString(), name = deviceInstance.InstanceName, guid = deviceInstance.InstanceGuid, id = i++ }); }
            i = 0;
            foreach (DeviceInstance deviceInstance in directInput.GetDevices(DeviceType.Mouse, DeviceEnumerationFlags.AllDevices))
            { devicesList.Add(deviceInstance.Type + "_" + deviceInstance.InstanceName + ":" + i); devices.Add(new Devices { type = deviceInstance.Type.ToString(), name = deviceInstance.InstanceName, guid = deviceInstance.InstanceGuid, id = i++ }); }
            i = 0;
            foreach (DeviceInstance deviceInstance in directInput.GetDevices(DeviceType.Keyboard, DeviceEnumerationFlags.AllDevices))
            { devicesList.Add(deviceInstance.Type + "_" + deviceInstance.InstanceName + ":" + i); devices.Add(new Devices { type = deviceInstance.Type.ToString(), name = deviceInstance.InstanceName, guid = deviceInstance.InstanceGuid, id = i++ }); }

            return devicesList;//return the list
        }

        public bool checkDevice( string type )
        {
            if (type == "jm" && jmDevice != null && jmDevice.IsDisposed) return false; else return true;//can be used to check if a device is found.
            if (type == "k" && kDevice != null && kDevice.IsDisposed) return false; else return true;//can be used to check if a device is found.
        }
        public void deleteDevice()
        {
            if ( jmDevice != null)  jmDevice.Dispose() ;        
            if ( kDevice != null)  kDevice.Dispose() ;      
        }
        public void setDeviceLock(bool inValue)
        {
            deviceLock = inValue;
        }
        public string getDeviceButton( int ID, string TYPE)
        {            
            //checks for button data, return if true state
            TYPE = TYPE.Substring(0,1);

            if (checkDevice("jm") && (TYPE == "J" || TYPE == "M" || TYPE == "G"))
            {
                jmDevice.GetCurrentState(ref jmDeviceState);
                int getButton = -1;
                //device.Poll(); not needed unless in loop the GetCurrentState does fine

                for ( int index=0; index < jmDeviceState.Buttons.Length; index++)
                    if (jmDeviceState.Buttons[ index]  == true)
                        getButton = index;

                if (getButton > -1) return ID.ToString() + "_" + TYPE + "_BTN" + getButton.ToString() + ":Button" + getButton.ToString() ; else return "Waiting...";
            }
            else if ( TYPE == "K" && checkDevice("k") )
            {
                kDevice.GetCurrentState( ref kDeviceState );
                int getButton = -1;
                //device.Poll(); not needed unless in loop the GetCurrentState does fine
                if ( kDeviceState.PressedKeys.Count > 0)
                    return ID.ToString() + "_" + TYPE + "_BTN" + kDeviceState.PressedKeys[ 0 ].ToString() + ":" + kDeviceState.PressedKeys[ 0 ].ToString() ;
                else
                    return "Waiting...";
            }
            return "...";
        }
        public string getDeviceAnalog( int ID, string TYPE )
        {
            TYPE = TYPE.Substring( 0, 1 );
            if ( TYPE == "K"  )  return "Waiting...";//only if device is joystick or mouse so return if not.
           
            jmDevice.GetCurrentState( ref jmDeviceState );
            int getAnalog = -1;
            //Console.WriteLine( deviceState.X.ToString() );

            if ( !deviceLock )
            {
                deviceLock = true;
                deviceStateX = jmDeviceState.X;
                deviceStateY = jmDeviceState.Y;
                deviceStateZ = jmDeviceState.Z;
                deviceStateXr = jmDeviceState.RotationX;
                deviceStateYr = jmDeviceState.RotationY;
                deviceStateZr = jmDeviceState.RotationZ;
            }
            float currentDeviceStateX = jmDeviceState.X;
            float currentDeviceStateY = jmDeviceState.Y;
            float currentDeviceStateZ = jmDeviceState.Z;
            float currentDeviceStatXr = jmDeviceState.RotationX;
            float currentDeviceStatYr = jmDeviceState.RotationY;
            float currentDeviceStatZr = jmDeviceState.RotationZ;

            float weight=0;
            int amount = 1000;//joystick
            if (TYPE == "M") amount = 100;//mouse

            // Find the analog that moved the most. use ABS for this to make it simple.
            if (Math.Abs(currentDeviceStateX - deviceStateX) > amount && Math.Abs(currentDeviceStateX - deviceStateX) > weight) { weight = Math.Abs(currentDeviceStateX - deviceStateX); getAnalog = 0; }
            if (Math.Abs(currentDeviceStateY - deviceStateY) > amount && Math.Abs(currentDeviceStateY - deviceStateY) > weight) { weight = Math.Abs(currentDeviceStateY - deviceStateY); getAnalog = 1; }
            if (Math.Abs(currentDeviceStateZ - deviceStateZ) > amount && Math.Abs(currentDeviceStateZ - deviceStateZ) > weight) { weight = Math.Abs(currentDeviceStateZ - deviceStateZ); getAnalog = 2; }
            if (Math.Abs(currentDeviceStatXr - deviceStateXr) > amount && Math.Abs(currentDeviceStatXr - deviceStateXr) > weight) { weight = Math.Abs(currentDeviceStatXr - deviceStateXr); getAnalog = 3; }
            if (Math.Abs(currentDeviceStatYr - deviceStateYr) > amount && Math.Abs(currentDeviceStatYr - deviceStateYr) > weight) { weight = Math.Abs(currentDeviceStatYr - deviceStateYr); getAnalog = 4; }
            if (Math.Abs(currentDeviceStatZr - deviceStateZr) > amount && Math.Abs(currentDeviceStatZr - deviceStateZr) > weight) { weight = Math.Abs(currentDeviceStatZr - deviceStateZr); getAnalog = 5; }

            //now find dirrection.
            string dir = "";
            if ( getAnalog > -1 && getAnalog == 0) dir = (currentDeviceStateX > deviceStateX) ? "+" : dir = "-";
            if ( getAnalog > -1 && getAnalog == 1) dir = (currentDeviceStateY > deviceStateY) ? "+" : dir = "-";
            if ( getAnalog > -1 && getAnalog == 2) dir = (currentDeviceStateZ > deviceStateZ) ? "+" : dir = "-";
            if ( getAnalog > -1 && getAnalog == 3) dir = (currentDeviceStatXr > deviceStateXr) ? "+" : dir = "-";
            if ( getAnalog > -1 && getAnalog == 4) dir = (currentDeviceStatYr > deviceStateYr) ? "+" : dir = "-";
            if ( getAnalog > -1 && getAnalog == 5) dir = (currentDeviceStatZr > deviceStateZr) ? "+" : dir = "-";
            if (TYPE == "M") dir = "";

            if ( getAnalog > -1 ) {deviceLock = false; return ID.ToString() + "_" + TYPE + "_ALG" + getAnalog.ToString() + ":" + dir + "analog" + getAnalog.ToString();}
            else
            return "Waiting...";
        }
        public void setDevice( int ID , string type)
        {
            if (jmDevice != null)
            {
                jmDevice.Dispose();
                while (jmDevice.IsDisposed == false) ;
            }
            foreach (Devices d in devices) 
            if (d.type== type && (d.id == ID) ) deviceGuid = d.guid;

            //start up the device. 
            if (type == "Gamepad" || type == "Joystick" || type == "Mouse")
            {
                jmDevice = new Joystick( directInput, deviceGuid );
                jmDeviceState = new JoystickState();
                jmDevice.Acquire();
            }
            if ( type == "Keyboard" )
            {
                //start up the device. 
                kDevice = new Keyboard( directInput);
                kDeviceState = new KeyboardState();
                kDevice.Acquire();
            }


         
        }  

    }
    
   
}

